class IUP_BUTTON
-- Creates an interface element that is a button. When selected, this element 
-- activates a function in the application. Its visual presentation can contain 
-- a text and/or an image.
--
-- Buttons with images and/or texts can not change its behavior after mapped. 
-- This is a creation dependency. But after creation the image can be changed 
-- for another image, and the text for another text.
--
-- Buttons are activated using Enter or Space keys.
--
-- Buttons are not activated if the user clicks inside the button but moves the 
-- cursor and releases outside the button area. Also in Windows the highlight 
-- feedback when that happens is different if the button has CANFOCUS enabled or
-- not.
--
-- Usually toolbar buttons have FLAT=True and CANFOCUS=False.

inherit
	IUP_WIDGET
		redefine
			execute_map,
			execute_unmap,
			execute_destroy,
			execute_getfocus,
			execute_killfocus,
			execute_enterwindow,
			execute_leavewindow,
			execute_k_any,
			execute_help,
			execute_action,
			execute_button
		end
	IUP_WIDGET_BGCOLOR
	IUP_WIDGET_FGCOLOR
	IUP_WIDGET_TITLE
	IUP_WIDGET_ACTIVE
	IUP_WIDGET_FONT
	IUP_WIDGET_EXPAND
	IUP_WIDGET_SCREENPOSITION
	IUP_WIDGET_POSITION
	IUP_WIDGET_MAXMIN_SIZE
	IUP_WIDGET_TIP
	IUP_WIDGET_SIZE
	IUP_WIDGET_RASTERSIZE
	IUP_WIDGET_USERSIZE
	IUP_WIDGET_ZORDER
	IUP_WIDGET_VISIBLE
	IUP_WIDGET_CHILD
	IUP_WIDGET_NAME
	IUP_WIDGET_FOCUS
	IUP_WIDGET_PROPAGATEFOCUS
	IUP_WIDGET_CUSTOM_ATTRIBUTES
	IUP_WIDGET_PADDING
	IUP_WIDGET_IMPRESS_BORDER
	IUP_WIDGET_IMAGE_POSITION
	IUP_WIDGET_SPACING
	IUP_WIDGET_CB_ACTION
	IUP_WIDGET_CB_BUTTON

create {ANY}
   button

create {IUP_GET_PARAM}
   button_widget

feature {ANY}
	
	button (title: STRING)
		-- New button with the specified title.
		local
			a, b, a_button: POINTER
		do
			if attached title as text then
				a := get_pointer(text.to_c)
			end

			a_button := int_button (a, b)
			set_widget(a_button)
		end

	-- Attributes

	set_alignment (horizontal, vertical: STRING)
		-- (non inheritable): horizontal and vertical alignment. Possible values: 
		-- "ALEFT", "ACENTER" and "ARIGHT",  combined to "ATOP", "ACENTER" and 
		-- "ABOTTOM". Default: "ACENTER:ACENTER". In Motif, vertical alignment is 
		-- restricted to "ACENTER". In GTK, horizontal alignment for multiple 
		-- lines will align only the text block.
		require
			is_valid_alignment(horizontal, vertical)
		local
			str: STRING
		do
			create str.make_from_string(horizontal)
	      str.append_string(":")
 	      str.append_string(vertical)
	
			iup_open.set_attribute(Current, "ALIGNMENT", str)
		end

	set_can_focus (state: BOOLEAN)
		-- (creation only) (non inheritable): enables the focus traversal of the 
		-- control. In Windows the button will respect CANFOCUS differently to 
		-- some other controls. Default: True.
		do
			iup_open.set_attribute(Current, "CANFOCUS", boolean_to_yesno(state))
		end

	set_flat (state: BOOLEAN)
		-- (creation only): Hides the button borders until the mouse cursor 
		-- enters the button area. Can be True or False. Default: False.
		do
			iup_open.set_attribute(Current, "FLAT", boolean_to_yesno(state))
		end

	set_image (name: STRING)
		-- (non inheritable): Image name. If set before map defines the behavior 
		-- of the button to contain an image. The natural size will be size of 
		-- the image in pixels, plus the button borders. Use set_widget_name 
		-- to associate an image to a name. See also IUP_IMAGE. If TITLE is also 
		-- defined and not empty both will be shown (except in Motif).
		do
			iup_open.set_attribute(Current, "IMAGE", name)
		end

	set_image_inactive (name: STRING)
		-- (non inheritable): Image name of the element when inactive. If it is 
		-- not defined then the IMAGE is used and the colors will be replaced by 
		-- a modified version of the background color creating the disabled 
		-- effect. GTK will also change the inactive image to look like other 
		-- inactive objects.
		do
			iup_open.set_attribute(Current, "IMINACTIVE", name)
		end

	set_image_press (name: STRING)
		-- (non inheritable): Image name of the pressed button. If IMPRESS and 
		-- IMAGE are defined, the button borders are not shown and not computed 
		-- in natural size. When the button is clicked the pressed image does not 
		-- offset. In Motif the button will lose its focus feedback also.
		do
			iup_open.set_attribute(Current, "IMPRESS", name)
		end

	set_markup (state: BOOLEAN)
		--  [GTK only]: allows the title string to contains pango markup 
		--  commands. Works only if a mnemonic is NOT defined in the title. Can 
		--  be "True" or "False". Default: "False". 
		do
			iup_open.set_attribute(Current, "MARKUP", boolean_to_yesno(state))
		end
	
	-- For callbacks

	-- Common
	set_cb_map (act: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING])
		-- Called right after an element is mapped and its attributes updated.
		local
			operation: INTEGER
		do
			cb_map := act
			
			if cb_map /= Void then
				operation := 1
			else
				operation := 0
			end
						
			iup_open.set_callback (Current, "MAP_CB", "NONEEDED", operation)
		end

	set_cb_unmap (act: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING])
		-- Called right before an element is unmapped.
		local
			operation: INTEGER
		do
			cb_unmap := act

			if cb_unmap /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "UNMAP_CB", "NONEEDED", operation)
		end

	set_cb_destroy (act: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING])
		-- Called right before an element is destroyed.
		local
			operation: INTEGER
		do
			cb_destroy := act

			if cb_destroy /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "DESTROY_CB", "NONEEDED", operation)
		end

	set_cb_get_focus (act: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING])
		-- Action generated when an element is given keyboard focus. 
		-- This callback is called after the KILLFOCUS_CB of the element 
		-- that loosed the focus. The {IUP}.get_focus function during the 
		-- callback returns the element that loosed the focus.
		local
			operation: INTEGER
		do
			cb_getfocus := act

			if cb_getfocus /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "GETFOCUS_CB", "NONEEDED", operation)
		end

	set_cb_kill_focus (act: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING])
		-- Action generated when an element loses keyboard focus. This 
		-- callback is called before the GETFOCUS_CB of the element that 
		-- gets the focus.
		local
			operation: INTEGER
		do
			cb_killfocus := act

			if cb_killfocus /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "KILLFOCUS_CB", "NONEEDED", operation)
		end

	set_cb_enter_window (act: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING])
		-- Action generated when the mouse enters the native element. 
		local
			operation: INTEGER
		do
			cb_enterwindow := act

			if cb_enterwindow /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "ENTERWINDOW_CB", "NONEEDED", operation)
		end

	set_cb_leave_window (act: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING])
		-- Action generated when the mouse leaves the native element.
		local
			operation: INTEGER
		do
			cb_leavewindow := act

			if cb_leavewindow /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "LEAVEWINDOW_CB", "NONEEDED", operation)
		end

	set_cb_k_any (act: detachable FUNCTION[TUPLE[IUP_BUTTON, INTEGER], STRING])
		-- Action generated when a keyboard event occurs.
		-- IUP_WIDGET the element that activated the event.
		-- INTEGER identifier of typed key. Please refer to the Keyboard 
		-- Codes table for a list of possible values.
		--
		-- Returns: If IUP_IGNORE is returned the key is ignored and not
		-- processed by the control and not propagated. If returns 
		-- IUP_CONTINUE, the key will be processed and the event will be
		-- propagated to the parent of the element receiving it, this is 
		-- the default behavior. If returns IUP_DEFAULT the key is processed 
		-- but it is not propagated. IUP_CLOSE will be processed. 
		local
			operation: INTEGER
		do
			cb_k_any := act

			if cb_k_any /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "K_ANY", "NONEEDED", operation)
		end

	set_cb_help (act: detachable PROCEDURE[TUPLE[IUP_BUTTON]])
		-- Action generated when the user press F1 at a control. In Motif 
		-- is also activated by the Help button in some workstations 
		-- keyboard.
		-- Returns: IUP_CLOSE will be processed.
		local
			operation: INTEGER
		do
			cb_help := act

			if cb_help /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "HELP_CB", "NONEEDED", operation)
		end

	-- Validations

	is_valid_alignment (horizontal, vertical: STRING): BOOLEAN
		local
			h, v: BOOLEAN
		do
			if horizontal.is_equal("ALEFT") or
				horizontal.is_equal("ACENTER") or
				horizontal.is_equal("ARIGHT") then
				h := True
			else
				h := False
			end

			if vertical.is_equal("ATOP") or
				vertical.is_equal("ACENTER") or
				vertical.is_equal("ABOTTOM") then
				v := True
			else
				v := False
			end

			if h and v then
				Result := True
			else
				Result := False
			end
		end


feature {IUP}

	-- Common callbacks
	
	execute_map: STRING
		do
			if attached cb_map as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_unmap: STRING
		do
			if attached cb_unmap as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_destroy: STRING
		do
			if attached cb_destroy as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_getfocus: STRING
		do
			if attached cb_getfocus as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_killfocus: STRING
		do
			if attached cb_killfocus as int_cb then
			Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_enterwindow: STRING
		do
			if attached cb_enterwindow as int_cb then
			Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_leavewindow: STRING
		do
			if attached cb_leavewindow as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_k_any (c: INTEGER): STRING
		do
			if attached cb_k_any as int_cb then
				Result := int_cb.item([Current, c])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_help
		do
			if attached cb_help as int_cb then
				int_cb.call([Current])
			end
		end

	execute_action: STRING
		do
			if attached cb_action as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	-- Extra

	execute_button (btn, pressed, x, y: INTEGER; status: STRING): STRING
		do
			if attached cb_button as int_cb then
				Result := int_cb.item([Current, btn, pressed, x, y, status])
			else
				Result := "IUP_DEFAULT"
			end
		end

feature {IUP_GET_PARAM}

	button_widget (a_button: POINTER)
		do
			set_widget(a_button)
		end
	
feature {NONE}

	-- For callbacks
	cb_map: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING]
	cb_unmap: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING]
	cb_destroy: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING]
	cb_getfocus: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING]
	cb_killfocus: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING]
	cb_enterwindow: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING]
	cb_leavewindow: detachable FUNCTION[TUPLE[IUP_BUTTON], STRING]
	cb_k_any: detachable FUNCTION[TUPLE[IUP_BUTTON, INTEGER], STRING]
	cb_help: detachable PROCEDURE[TUPLE[IUP_BUTTON]]
	
	-- Internals
	
	int_button (title: POINTER; action: POINTER): POINTER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return IupButton ($title, $action);"
      end

end -- end IUP_BUTTON

-- The MIT License (MIT)

-- Copyright (c) 2016, 2017, 2019, 2020 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
